home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Cream of the Crop 1
/
Cream of the Crop 1.iso
/
PROGRAM
/
UUPC11QS.ARJ
/
DCPGPKT.C
< prev
next >
Wrap
C/C++ Source or Header
|
1991-11-17
|
35KB
|
1,057 lines
/*
For best results in visual layout while viewing this file, set
tab stops to every 4 columns.
*/
/*
dcpgpkt.c
Revised edition of dcp
Stuart Lynne May/87
Copyright (c) Richard H. Lamb 1985, 1986, 1987
Changes Copyright (c) Stuart Lynne 1987
Maintenance notes:
25Aug87 - Allow for up to 7 windows - Jal
01Nov87 - those strncpy's should really be memcpy's! - Jal
11Sep89 - Raise TimeOut to 15 - ahd
30Apr90 - Add Jordon Brown's fix for short packet retries.
Reduce retry limit to 20 ahd
22Jul90 - Change error retry limit from per host to per
packet. ahd
22Jul90 - Add error message for number of retries exceeded ahd
08Sep90 - Drop memmove to memcpy change supplied by Jordan
Brown, MS 6.0 and Turbo C++ agree memmove insures
no overlap
*/
/* "DCP" a uucp clone. Copyright Richard H. Lamb 1985,1986,1987 */
/* 7-window "g" ptotocol */
/*
Thanks goes to John Gilmore for sending me a copy of Greg Chesson's
UUCP protocol description -- Obviously invaluable.
Thanks also go to Andrew Tannenbaum for the section on Siding window
protocols with a program example in his "Computer Networks" book.
*/
#include <stdio.h>
#include <string.h>
#include <time.h>
#include "lib.h"
#include "dcp.h"
#include "dcpsys.h"
#include "dcpgpkt.h"
#include "hostable.h"
#include "security.h"
#include "ulib.h"
#include "modem.h"
#define PKTSIZE 64
#define PKTSIZ2 2 /* 8x(2**2) = 64 */
#define HDRSIZE 6
#define MAXTRY 4
/*--------------------------------------------------------------------*/
/* g-packet type definitions */
/*--------------------------------------------------------------------*/
#define DATA 0
#define CLOSE 1
#define NAK 2
#define SRJ 3
#define ACK 4
#define INITC 5
#define INITB 6
#define INITA 7
#define POK -1
#define MAXWINDOW 7
#define NBUF 8 /* always SAME as MAXSEQ ? */
#define MAXSEQ 8
#define between(a,b,c) ((a<=b && b<c) || \
(c<a && a<=b) || \
(b<c && c<a))
#define nextpkt(x) ((x + 1) % MAXSEQ)
/*--------------------------------------------------------------------*/
/* Global variables for packet definitions */
/*--------------------------------------------------------------------*/
static int rwl, swl, swu, rwu, nbuffers, irec, lazynak;
static INTEGER nerr;
static int outlen[NBUF], inlen[NBUF], arrived[NBUF];
static int nwindows, maxwindows;
static char outbuf[NBUF][PKTSIZE+1], inbuf[NBUF][PKTSIZE+1];
static long ftimer[NBUF];
static int timeouts, outsequence, naksin, naksout, screwups;
static int reinit, shifts, badhdr, resends;
/*--------------------------------------------------------------------*/
/* Internal function prototypes */
/*--------------------------------------------------------------------*/
static int gmachine(const int timeout);
static void gspack(int type,int yyy,int xxx,int len,char *data);
static int grpack(int *yyy,
int *xxx,
int *len,
char *data,
const int timeout);
static void gstats( void );
static unsigned int checksum(char *data, int len);
/****************** SUB SUB SUB PACKET HANDLER ************/
/*
g o p e n p k
*/
int gopenpk()
{
int i, xxx, yyy, len;
char tmp[PKTSIZE+1];
pktsize = PKTSIZE; /* change it later after the init */
maxwindows = GetGWindow( MAXWINDOW );
/*--------------------------------------------------------------------*/
/* Initialize error counters */
/*--------------------------------------------------------------------*/
timeouts = outsequence = naksin = naksout = screwups =
shifts = badhdr = resends = reinit = 0;
/*--------------------------------------------------------------------*/
/* Initialize proto parameters */
/*--------------------------------------------------------------------*/
nerr = nbuffers = 0;
swl = swu = 1;
rwl = 0;
nwindows = maxwindows;
rwu = nwindows - 1;
if ( PortTimeout == 0 )
PortTimeout = PacketTimeout * 2 - 1;
for (i = 0; i < NBUF; i++) {
ftimer[i] = 0;
arrived[i] = FALSE;
}
/*--------------------------------------------------------------------*/
/* 3-way handshake */
/*--------------------------------------------------------------------*/
gspack(INITA, 0, 0, 0, tmp);
rsrt:
if (nerr >= MaxErr)
{
remote_stats.errors += nerr;
nerr = 0;
printmsg(0,
"gopenpk: Consecutive error limit of %ld exceeded, %ld total errors",
(long) MaxErr, remote_stats.errors);
return(FAILED);
}
/*--------------------------------------------------------------------*/
/* INIT sequence. Easy fix for variable packet size. I didn't */
/* since all the machines I talk to use PKTSZ=64. If you do */
/* this make sure to reflect the changes in "grpack" and */
/* "gspack" */
/*--------------------------------------------------------------------*/
switch (grpack(&yyy, &xxx, &len, tmp, PacketTimeout )) {
case INITA:
printmsg(5, "**got INITA");
nwindows = yyy;
if (nwindows > maxwindows)
nwindows = maxwindows;
rwu = nwindows - 1;
gspack(INITB, 0, 0, 0, tmp); /* data segment (packet) size */
goto rsrt;
case INITB:
printmsg(5, "**got INITB");
gspack(INITC, 0, 0, 0, tmp);
goto rsrt;
case INITC:
printmsg(5, "**got INITC");
break;
default:
nerr++;
screwups++;
printmsg(5, "**got SCREW UP");
gspack(INITA, 0, 0, 0, tmp);
goto rsrt;
}
nerr = 0;
lazynak = 0;
return(OK); /* channel open */
} /*gopenpk*/
/*--------------------------------------------------------------------*/
/* g f i l e p k t */
/* */
/* Begin a file transfer (not used by "g" protocol) */
/*--------------------------------------------------------------------*/
int gfilepkt( void )
{
return OK;
} /* gfilepkt */
/*--------------------------------------------------------------------*/
/* g c l o s e p k */
/* */
/* Close packet machine */
/*--------------------------------------------------------------------*/
int gclosepk()
{
int i;
char tmp[PKTSIZE+1];
for (i = 0; i < MAXTRY; i++) {
gspack(CLOSE, 0, 0, 0, tmp);
if (gmachine(PacketTimeout) == CLOSE)
break;
}
gstats();
return(0);
} /*gclosepk*/
/*--------------------------------------------------------------------*/
/* g s t a t s */
/* */
/* Report summary of errors for processing */
/*--------------------------------------------------------------------*/
static void gstats( void )
{
remote_stats.errors += nerr;
nerr = 0;
if ( remote_stats.errors || shifts || badhdr )
{
printmsg(0,
"%d time outs, %d port reinits, %d out of seq pkts, \
%d NAKs rec, %d NAKs sent",
timeouts, reinit, outsequence, naksin, naksout);
printmsg(0,
"%d invalid pkt types, %d re-syncs, %d bad pkt hdrs, %d pkts resent",
screwups, shifts, badhdr, resends);
}
}
/*
g g e t p k t
Gets no more than a packet's worth of data from
the "packet I/O state machine". May have to
periodically run the packet machine to get some packets.
on input: don't care
on return: data+\0 and length in len.
ret(0) if all's well
ret(-1) if problems (failed)
*/
int ggetpkt(char *data, int *len)
{
int i;
int retry = MaxErr;
time_t start;
#ifdef _DEBUG
int savedebug = debuglevel;
#endif
irec = 1;
time( &start );
/*--------------------------------------------------------------------*/
/* Loop to wait for the desired packet */
/*--------------------------------------------------------------------*/
while (!arrived[rwl] && retry)
{
if (gmachine(PacketTimeout) != POK)
return(-1);
if (!arrived[rwl] )
{
time_t now;
if (time( &now ) > (start + PacketTimeout) )
{
#ifdef _DEBUG
if ( debuglevel < 6 )
debuglevel = 6;
#endif
printmsg(5,"ggetpkt: Timeout %d waiting for inbound packet %d",
MaxErr - --retry, remote_stats.packets + 1);
timeouts++;
start = now;
} /* if (time( now ) > (start + PacketTimeout) ) */
} /* if (!arrived[rwl] ) */
} /* while (!arrived[rwl] && i) */
#ifdef _DEBUG
debuglevel = savedebug;
#endif
if (!arrived[rwl])
{
printmsg(0,"ggetpkt: Remote host failed to respond after %ld seconds",
(long) PacketTimeout * MaxErr);
gclosepk();
return -1;
}
/*--------------------------------------------------------------------*/
/* Got a packet! */
/*--------------------------------------------------------------------*/
i = rwl; /*<-- mod(,rwindow) for larger than 8 seq no.s */
*len = inlen[i];
memcpy(data, inbuf[i], *len);
arrived[i] = FALSE;
rwu = nextpkt(rwu) ; /* bump receive window */
return(0);
} /*ggetpkt*/
/*
g s e n d p k t
Put at most a packet's worth of data in the packet state
machine for transmission.
May have to run the packet machine a few times to get
an available output slot.
on input: data=*data; len=length of data in data.
return:
0 if all's well
-1 if problems (failed)
*/
int gsendpkt(char *data, int len)
{
int i1;
#ifdef _DEBUG
int savedebug = debuglevel;
#endif
irec = 0;
/* WAIT FOR INPUT i.e. if weve sent SWINDOW pkts and none have been
acked, wait for acks */
while (nbuffers >= nwindows)
if (gmachine(0) != POK) /* Spin with no timeout */
return(-1);
i1 = swu; /* <--If we ever have more than 8 seq no.s, must mod() here */
/*--------------------------------------------------------------------*/
/* Place packet in table and mark unacked */
/*--------------------------------------------------------------------*/
memcpy(outbuf[i1], data, len);
/*--------------------------------------------------------------------*/
/* Handle short packets. */
/*--------------------------------------------------------------------*/
if(len < PKTSIZE) {
memmove(outbuf[i1] + 1, outbuf[i1], PKTSIZE - 1);
outbuf[i1][0] = (unsigned char) (PKTSIZE - len);
memset(outbuf[i1]+len+1, 0, PKTSIZE-len-1);
/* Pad with nulls. Ugh. */
}
/*--------------------------------------------------------------------*/
/* Mark packet */
/*--------------------------------------------------------------------*/
outlen[i1] = len;
ftimer[i1] = time(nil(long));
swu = nextpkt(swu); /* bump send window */
nbuffers++;
/*--------------------------------------------------------------------*/
/* send it */
/*--------------------------------------------------------------------*/
gspack(DATA, rwl, i1, outlen[i1], outbuf[i1]);
#ifdef _DEBUG
debuglevel = savedebug;
#endif
return(0);
} /*gsendpkt*/
/*--------------------------------------------------------------------*/
/* g e o f p k t */
/* */
/* Transmit EOF to the other system */
/*--------------------------------------------------------------------*/
int geofpkt( void )
{
char outbuf[PKTSIZE+1];
if (gsendpkt(outbuf, 0)) /* Empty packet == EOF */
return FAILED;
else
return OK;
} /* geofpkt */
/*--------------------------------------------------------------------*/
/* g w r m s g */
/* */
/* Send a message to remote system */
/*--------------------------------------------------------------------*/
int gwrmsg( char *s )
{
for(; strlen(s) >= pktsize; s += pktsize) {
int result = gsendpkt(s, pktsize);
if (result)
return result;
}
return gsendpkt(s, strlen(s)+1);
} /* gwrmsg */
/*--------------------------------------------------------------------*/
/* g r d m s g */
/* */
/* Read a message from the remote system */
/*--------------------------------------------------------------------*/
int grdmsg( char *s)
{
for ( ;; )
{
int len;
int result = ggetpkt( s, &len );
if (result || (s[len-1] == '\0'))
return result;
s += len;
} /* for */
} /* grdmsg */
/********** Packet Machine ********** RH Lamb 3/87 */
/*--------------------------------------------------------------------*/
/* g m a c h i n e */
/* */
/* Ideally we would like to fork this process off in an */
/* infinite loop and send and receive packets through "inbuf" */
/* and "outbuf". Can't do this in MS-DOS so we setup "getpkt" */
/* and "sendpkt" to call this routine often and return only */
/* when the input buffer is empty thus "blocking" the packet- */
/* machine task. */
/*--------------------------------------------------------------------*/
static int gmachine(const int timeout )
{
static time_t idletimer = 0;
static time_t acktimer = 0;
boolean done = FALSE; /* True = drop out of machine loop */
boolean close = FALSE; /* True = terminate connection upon
exit */
boolean inseq = TRUE; /* True = Count next out of sequence
packet as an error */
char rdata[PKTSIZE+1];
while ( !done )
{
boolean resend = FALSE; /* True = resend data packets */
boolean donak = FALSE; /* True = NAK the other system */
unsigned long packet_no = remote_stats.packets;
int pkttype, rack, rseq, rlen, i1;
time_t now;
if ( debuglevel >= 7 ) /* Optimize processing a little bit */
{
printmsg(10, "* send %d < W < %d, receive %d < W < %d, error %d",
swl, swu, rwl, rwu, nerr);
/*--------------------------------------------------------------------*/
/* Waiting for ACKs for swl to swu-1. Next pkt to send=swu */
/* rwl=expected pkt */
/*--------------------------------------------------------------------*/
printmsg(7, "Bytes transfered %ld errors %d",
(long) (remote_stats.packets * PKTSIZE) , nerr);
}
/*--------------------------------------------------------------------*/
/* Attempt to retrieve a packet and handle it */
/*--------------------------------------------------------------------*/
pkttype = grpack(&rack, &rseq, &rlen, rdata, timeout);
time(&now);
switch (pkttype) {
case CLOSE:
remote_stats.packets++;
printmsg(5, "**got CLOSE");
close = done = TRUE;
break;
case EMPTY:
printmsg(6, "**got EMPTY");
if (acktimer && (acktimer <= (now - PortTimeout)))
{
printmsg(5,"*** port re-init");
reinit++;
flowcontrol( FALSE );
acktimer = now;
}
if (ftimer[swl])
{
printmsg(6, "---> seq, elapst %d %ld", swl,
ftimer[swl] - now);
if ( ftimer[swl] <= (now - PacketTimeout))
{
printmsg(4, "*** timeout %d (%ld)",
swl, (long) remote_stats.packets);
/* Since "g" is "go-back-N", when we time out we
must send the last N pkts in order. The generalized
sliding window scheme relaxes this reqirment. */
nerr++;
timeouts++;
resend = TRUE;
} /* if */
} /* if */
else if (now > (idletimer + PacketTimeout))
printmsg(2,"*** BORED");
done = TRUE;
break;
case DATA:
printmsg(5, "**got DATA %d %d", rack, rseq);
i1 = nextpkt(rwl); /* (R+1)%8 <-- -->(R+W)%8 */
if (i1 == rseq) {
lazynak--;
remote_stats.packets++;
idletimer = now;
inseq = arrived[i1] = TRUE;
inlen[i1] = rlen;
memcpy(inbuf[i1], rdata, rlen);
rwl = i1;
printmsg(5, "*** ACK d %d", rwl);
gspack(ACK, rwl, 0, 0, rdata);
done = TRUE; /* return to caller when finished */
/* in a mtask system, unneccesary */
} else {
if (inseq || ( now > (idletimer + PacketTimeout)))
{
donak = TRUE; /* Only flag first out of sequence
packet as error, since we know
following ones also bad */
outsequence++;
inseq = FALSE;
}
printmsg(5, "*** unexpect %d ne %d (%d - %d)",
rseq, i1, rwl, rwu);
} /* else */
if ( swl == swu ) /* We waiting for an ACK? */
break; /* No --> Skip ACK processing */
/* else Fall through to ACK case */
case NAK:
case ACK:
if (pkttype == NAK)
{
nerr++;
naksin++;
printmsg(5, "**got NAK %d", rack);
resend = TRUE;
}
else if (pkttype == ACK)
printmsg(5, "**got ACK %d", rack);
acktimer = now;
while(between(swl, rack, swu))
{ /* S<-- -->(S+W-1)%8 */
remote_stats.packets++;
printmsg(5, "*** ACK %d", swl);
ftimer[swl] = 0;
idletimer = acktimer;
nbuffers--;
done = TRUE; /* Get more data for input */
swl = nextpkt(swl);
} /* while */
if (!done && (pkttype == ACK)) /* Find packet? */
{
printmsg(0,"*** ACK for bad packet %d (%d - %d)",
rack, swl, swu);
} /* if */
break;
case ERROR:
printmsg(5, "*** got BAD CHK");
acktimer = now;
naksout++;
donak = TRUE;
lazynak = 0; /* Always NAK bad checksum */
break;
default:
screwups++;
nerr++;
printmsg(5, "*** got SCREW UP");
break;
} /* switch */
/*--------------------------------------------------------------------*/
/* If we received an NAK or timed out, resend data packets */
/*--------------------------------------------------------------------*/
if ( resend )
for (rack = swl; between(swl, rack, swu); rack = nextpkt(rack))
{ /* resend rack->(swu-1) */
resends++;
gspack(DATA, rwl, rack, outlen[rack], outbuf[rack]);
printmsg(5, "*** resent %d", rack);
idletimer = ftimer[rack] = now;
} /* for */
/*--------------------------------------------------------------------*/
/* If we have an error and have not recently sent a NAK, do so now. */
/* We then reset our counter so we receive at least a window full of */
/* packets before sending another NAK */
/*--------------------------------------------------------------------*/
if ( donak )
{
nerr++;
if ( (lazynak < 1) || (now > (idletimer + PacketTimeout)))
{
printmsg(5, "*** NAK d %d", rwl);
gspack(NAK, rwl, 0, 0, rdata);
naksout++;
idletimer = now;
lazynak = nwindows + 1;
} /* if ( lazynak < 1 ) */
} /* if ( donak ) */
/*--------------------------------------------------------------------*/
/* Update error counter if needed */
/*--------------------------------------------------------------------*/
if ((close || (packet_no != remote_stats.packets)) && (nerr > 0))
{
printmsg(2,"gmachine: Packet %ld had %ld errors during transfer",
remote_stats.packets, (long) nerr);
remote_stats.errors += nerr;
nerr = 0;
}
/*--------------------------------------------------------------------*/
/* If we have an excessive number of errors, drop out of the */
/* loop */
/*--------------------------------------------------------------------*/
if (nerr >= MaxErr)
{
printmsg(0,
"gmachine: Consecutive error limit of %d exceeded, %d total errors",
MaxErr, nerr + remote_stats.errors);
done = close = TRUE;
gstats();
}
} /* while */
/*--------------------------------------------------------------------*/
/* Return to caller, gracefully terminating packet machine if */
/* requested */
/*--------------------------------------------------------------------*/
if ( close )
{
gspack(CLOSE, 0, 0, 0, rdata);
return CLOSE;
}
else
return POK;
} /*gmachine*/
/*************** FRAMING *****************************/
/*
g s p a c k
Send a packet
type=type yyy=pkrec xxx=timesent len=length<=PKTSIZE data=*data
ret(0) always
*/
static void gspack(int type, int yyy, int xxx, int len, char *data)
{
unsigned int check, i;
unsigned char header[HDRSIZE];
#ifdef LINKTEST
/***** Link Testing Mods *****/
unsigned char dpkerr[10];
/***** End Link Testing Mods *****/
#endif /* LINKTEST */
#ifdef LINKTEST
/***** Link Testing Mods - create artificial errors *****/
printf("**n:normal,e:error,l:lost,p:partial,h:bad header,s:new seq--> ");
gets(dpkerr);
if (dpkerr[0] == 's')
sscanf(&dpkerr[1], "%d", &xxx);
/***** End Link Testing Mods *****/
#endif /* LINKTEST */
printmsg(5, "send packet type %d, yyy=%d, xxx=%d, len=%d",
type, yyy, xxx, len);
header[0] = '\020';
type %= 8;
header[4] = (unsigned char) (type << 3);
switch (type) {
case CLOSE:
break; /* stop protocol */
case NAK:
header[4] += yyy;
break; /* reject */
case SRJ:
break;
case ACK:
header[4] += yyy;
break; /* ack */
case INITC:
header[4] += nwindows;
break;
case INITB:
header[4] += 1;
break; /* pktsiz = 64 (1) */
case INITA:
header[4] += maxwindows;
break;
case DATA:
header[4] = (unsigned char) (0x80 + (xxx << 3) + yyy);
/* havn't set it up for VERY LONG packets with a few
bytes yet (-128) */
if (len < PKTSIZE) { /* short packet? */
header[4] |= 0x40;
printmsg(7, "data=|%.*s|", len+1, data);
/* Count byte is handled at a higher level. */
/* Header construction should probably be handled there too. */
} else printmsg(7, "data=|%.*s|", len, data);
break;
}
if (type != DATA) {
header[1] = 9; /* control packet size = 0 (9) */
check = (0xaaaa - header[4]) & 0xffff;
} else {
header[1] = PKTSIZ2; /* data packet size = 64 (2) */
check = checksum(data, PKTSIZE);
i = header[4]; /* got to do this on PC for ex-or high bits */
i &= 0xff;
check = (check ^ i) & 0xffff;
check = (0xaaaa - check) & 0xffff;
}
header[2] = (unsigned char) (check & 0xff);
header[3] = (unsigned char) ((check >> 8) & 0xff);
header[5] = (unsigned char)
((header[1] ^ header[2] ^ header[3] ^ header[4]) & 0xff) ;
#ifdef LINKTEST
/***** More Link Testing Mods *****/
switch(dpkerr[0]) {
case 'e':
data[10] = - data[10];
break;
case 'h':
header[5] = - header[5];
break;
case 'l':
return;
case 'p':
swrite((char *) header, HDRSIZE);
if (header[1] != 9)
swrite(data, PKTSIZE - 3);
return;
default:
break;
}
/***** End Link Testing Mods *****/
#endif /* LINKTEST */
swrite((char *) header, HDRSIZE); /* header is 6-bytes long */
if (header[1] != 9)
swrite(data, PKTSIZE); /* data is always 64 bytes long */
} /*gspack*/
/*
g r p a c k
Read packet
on return: yyy=pkrec xxx=pksent len=length<=PKTSIZE data=*data
ret(type) ok
ret(EMPTY) input buf empty
ret(ERROR) bad header
ret(EMPTY) lost packet timeout
ret(ERROR) checksum error
ret(-5) packet size != 64
NOTE (specifications for sread()):
sread(buf, n, timeout)
while(TRUE) {
if (# of chars available >= n) (without dec internal counter)
read n chars into buf (decrement internal char counter)
break
else
if (time > timeout)
break;
}
return(# of chars available)
*/
static int grpack(int *yyy, int *xxx, int *len, char *data, const int timeout)
{
static int got_hdr = FALSE;
static unsigned char grpkt[PKTSIZE+HDRSIZE];
static int received = 0; /* Bytes already read into buffer */
int needed;
unsigned int type, check, checkchk, i, total;
unsigned char c, c2;
time_t start;
if (got_hdr)
goto get_data;
/*--------------------------------------------------------------------*/
/* Spin up to timeout waiting for a Control-P, our sync character */
/*--------------------------------------------------------------------*/
start = 0;
while (!got_hdr)
{
unsigned char *psync;
needed = HDRSIZE - received;
if ( needed > 0 ) /* Have enough bytes for header? */
{ /* No --> Read as much as we need */
int wait;
if ( start == 0 ) /* First pass through data? */
{ /* Yes --> Set timers up */
start = time(nil(time_t));
wait = timeout;
} /* if ( start == 0 ) */
else {
wait = (int) (time(NULL) - start) - timeout;
if (wait < 0) /* Negative timeout? */
wait = 0; /* Make it no time out */
} /* else */
if (sread((char *) &grpkt[received], needed, wait ) < (unsigned) needed )
/* Did we get the needed data? */
return EMPTY; /* No --> Return to caller */
received += needed;
} /* if ( needed < received ) */
/*--------------------------------------------------------------------*/
/* Search for sync character in newly read data */
/*--------------------------------------------------------------------*/
printmsg(10,"grpack: Have %d characters after reading %d",
received, needed);
psync = memchr( grpkt, '\020', received );
if ( psync == NULL ) /* Did we find the sync character? */
received = 0; /* No --> Reset to empty buffer */
else if ( psync != grpkt ) /* First character in buffer? */
{ /* No --> Make it first character */
received -= psync - grpkt;
shifts++;
memmove( grpkt, psync, received );
/* Shift buffer over */
} /* else */
/*--------------------------------------------------------------------*/
/* If we have read an entire packet header, then perform a */
/* simple XOR checksum to determine if it is valid. If we have */
/* a valid checksum, drop out of this search, else drop the */
/* sync character and restart the scan. */
/*--------------------------------------------------------------------*/
if ( received >= HDRSIZE )
{
i = (unsigned) (grpkt[1] ^ grpkt[2] ^ grpkt[3] ^
grpkt[4] ^ grpkt[5]);
i &= 0xff;
printmsg(i ? 2 : 10, "prpkt %02x %02x %02x %02x %02x .. %02x ",
grpkt[1], grpkt[2], grpkt[3], grpkt[4], grpkt[5], i);
if (i == 0) /* Good header? */
got_hdr = TRUE; /* Yes --> Drop out of loop */
else { /* No --> Flag it, continue loop */
badhdr++;
printmsg(2, "*** bad pkt header ***");
memmove( grpkt, &grpkt[ 1 ], --received );
/* Begin scanning for sync character
with next byte */
} /* else */
} /* if ( received > HDRSIZE ) */
} /* while */
/*--------------------------------------------------------------------*/
/* Handle control packets */
/*--------------------------------------------------------------------*/
if (grpkt[1] == 9)
{
*data = '\0';
*len = 0;
c = grpkt[4];
type = c >> 3;
*yyy = c & 0x07;
*xxx = 0;
check = 0;
checkchk = 0;
got_hdr = FALSE;
}
/*--------------------------------------------------------------------*/
/* Handle data packets */
/*--------------------------------------------------------------------*/
else {
get_data:
total = 8 * (2 << grpkt[1]);
if (total > PKTSIZE)
{
printmsg(0,"grpack: Invalid packet size %d (%d)",
total, (int) grpkt[1]);
received = 0;
got_hdr = FALSE;
return(-5); /* can't handle packet size other than 64 */
}
needed = total + HDRSIZE - received;
if ((needed > 0) &&
(sread(&data[total - needed], needed , timeout) < (unsigned)needed))
return(EMPTY);
if ( received > HDRSIZE )
memmove( data, &grpkt[HDRSIZE], received - HDRSIZE);
got_hdr = FALSE;
type = 0;
c2 = grpkt[4];
c = (unsigned char) (c2 & 0x3f);
*xxx = c >> 3;
*yyy = c & 0x07;
i = grpkt[3];
i = (i << 8) & 0xff00;
check = grpkt[2];
check = i | (check & 0xff);
checkchk = checksum(data, total);
i = grpkt[4] | 0x80;
i &= 0xff;
checkchk = 0xaaaa - (checkchk ^ i);
checkchk &= 0xffff;
if (checkchk != check) {
printmsg(4, "*** checksum error ***");
memmove( grpkt, data, total );
/* Save data so we can scan for sync */
received = total; /* Note the amount of the data in buf */
return(ERROR); /* Return to caller with error */
}
*len = total;
/* Haven't set it up for very long pkts yet (>128). RH Lamb */
if (c2 & 0x40) {
int ii;
ii = (data[0] & 0xff);
*len = (*len - ii) & 0xff;
memmove(data, data + 1, *len);
}
} /* else */
/*--------------------------------------------------------------------*/
/* Announce what we got and return to the caller */
/*--------------------------------------------------------------------*/
received = 0; /* Returning entire buffer, reset count */
printmsg(5, "receive packet type %d, yyy=%d, xxx=%d, len=%d",
type, *yyy, *xxx, *len);
printmsg(13, " checksum rec=%04x comp=%04x\ndata=|%.*s|",
check, checkchk, total, data);
return(type);
} /*grpack*/
/*
c h e c k s u m
*/
static unsigned int checksum(char *data, int len)
{
int i, j;
unsigned int tmp, chk1, chk2;
chk1 = 0xffff;
chk2 = 0;
j = len;
for (i = 0; i < len; i++) {
if (chk1 & 0x8000) {
chk1 <<= 1;
chk1++;
} else {
chk1 <<= 1;
}
tmp = chk1;
chk1 += (data[i] & 0xff);
chk2 += chk1 ^ j;
if ((chk1 & 0xffff) <= (tmp & 0xffff))
chk1 ^= chk2;
j--;
}
return(chk1 & 0xffff);
} /*checksum*/